#include "..\include\ListenSocket.h"

using namespace std;

CListenSocket::CListenSocket(USHORT nPort, AcceptCB callback):mIsAlive(TRUE), mPort(nPort), mCallBack(callback)
{
}

CListenSocket::~CListenSocket()
{
	Exit();
}

BOOL CListenSocket::Start()
{
	if (!mCallBack) {
		return FALSE;
	}
	mListenThread = new thread(ListenThread, this);
	if (mListenSocket) {
		return FALSE;
	}
	return TRUE;
}

void CListenSocket::Exit()
{
	mIsAlive = FALSE;
	closesocket(mListenSocket);
	if (mListenThread) {
		mListenThread->detach();
		mListenThread = NULL;
	}
}

void CListenSocket::AcceptClient()
{
	SOCKADDR_IN clientAddr;
	int addrlen = sizeof(clientAddr);
	SOCKET sClient = accept(mListenSocket, (sockaddr*)&clientAddr, &addrlen);

	mCallBack(sClient, clientAddr);
}

void CListenSocket::ListenThread(LPVOID argv)
{
	CListenSocket*mThis = reinterpret_cast<CListenSocket*>(argv);
	if (!mThis)
		return;

	mThis->mListenSocket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(mThis->mPort);
	sin.sin_addr.S_un.S_addr = INADDR_ANY;

	if (::bind(mThis->mListenSocket, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
	{
		closesocket(mThis->mListenSocket);
		return;
	}
	mThis->mEvent = ::WSACreateEvent();
	::WSAEventSelect(mThis->mListenSocket, mThis->mEvent, FD_ACCEPT | FD_CLOSE);

	::listen(mThis->mListenSocket, 5);

	while (mThis->mIsAlive) {
		DWORD nResult = WaitForSingleObject(mThis->mEvent, INFINITE);
		if (nResult == WAIT_OBJECT_0)
		{
			WSANETWORKEVENTS ne;
			WSAEnumNetworkEvents(mThis->mListenSocket, mThis->mEvent, &ne);
			WSAResetEvent(mThis->mEvent);
			if (ne.lNetworkEvents& FD_ACCEPT) {
				mThis->AcceptClient();
			}
			else if (ne.lNetworkEvents& FD_CLOSE) {
				mThis->Exit();
				break;
			}
		}
	};
}
